/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "渲染节点.h"


#include <file_文件名数据.h>
#include <物体/物体.h>
#include <物体/S_摄像机.h>
#include <场景/intern/S_Scene.h>
#include <OpenImageDenoise/oidn.h>
#include <OpenImageDenoise/oidn.hpp>

#include <Context/当前默认操作数据.h>
#include <Context/节点数据操作.h>
#include "Context/数据创建销毁.h"
#include "节点编辑.h"

#include "节点/插座/字符插座.h"
#include "节点/插座/list/list物体插座.h"
#include "节点/插座/list/list数值插座.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/材质纹理插座.h"
#include "节点/插座/C_物体插座.h"
#include "节点/插座/list/list矢量插座.h"

#include "节点/socket_utils.h"

#include "异步解算/物理异步解算.h"



static void on_设置路径更新节点(S_Props& prop) {
	E_对话框类型 类型 = E_对话框类型::e_写入;

	//f_ui_set路径编辑框对话框类型(prop.m_部件, 类型);
	//f_ui_set路径编辑框对话框后缀(prop.m_部件, ".png");
	f_ui_set路径编辑框对话框类型(prop.m_UI->m_部件, 类型);
	f_ui_set路径编辑框对话框后缀(prop.m_UI->m_部件, ".png");
}




C_渲染器配置节点::C_渲染器配置节点(S_设备环境& ctx) : C_节点基类(DEF_渲染器配置节点, E_节点类型::e_节点Type_渲染) {
	f_setWName(u"渲染器");
	m_Ctx = ctx;
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	C_插座基类* socket;
	DEF_创建物体插座_I(u"摄像机");
	DEF_创建材质插座_I(u"环境材质");

	DEF_创建纹理_1D插座_O(u"图像", ctx);



	m_分辨率 = f_alloc_uVec2Prop(nullptr, u"分辨率", { 1920,1080 }, 0, 1000000);
	m_分辨率.m_私有 = true;
	m_光反弹 = f_alloc_UI32Prop(nullptr, u"光反弹", 8, 0, 1000000);
	m_光反弹.m_私有 = true;
	m_光采样 = f_alloc_UI32Prop(nullptr, u"光采样", 8, 0, 1000000);
	m_光采样.m_私有 = true;
	m_采样 = f_alloc_UI32Prop(nullptr, u"采样", 256, 0, 1000000);
	m_采样.m_私有 = true;

	m_瓦片渲染 = f_alloc_BoolProp(nullptr, u"瓦片渲染", false);
	m_瓦片渲染.m_私有 = true;

	m_瓦片大小 = f_alloc_uVec2Prop(nullptr, u"瓦块大小", { 256, 256 }, 1, 1000000);
	m_瓦片大小.m_私有 = true;


	m_开启运动模糊 = f_alloc_BoolProp(nullptr, u"运动模糊", false);
	m_开启运动模糊.m_私有 = true;

	m_运动模糊采样 = f_alloc_UI32Prop(nullptr, u"运动模糊采样", 10, 0, 10);
	m_运动模糊采样.m_私有 = true;

	m_运动模糊时间 = f_alloc_F32Prop(nullptr, u"运动模糊时间", 0.5);
	m_运动模糊时间.m_私有 = true;




	//m_渲染纹理 = f_tex_创建帧缓存纹理(m_Ctx, { 1024, 1024, 1 }, E_纹理格式::e_tf_RGBA8U_U, E_纹理维度类型::e_2D);
	m_渲染纹理 = f_tex_创建帧缓存纹理(m_Ctx, { 1024, 1024, 1 }, E_纹理格式::e_tf_RGBA32, E_纹理维度类型::e_2D);

	static S_纹理采样器* 默认采样器 = f_tex_创建纹理采样器(ctx);
	f_tex_安装纹理采样器(m_渲染纹理, 默认采样器);



	m_输出图层 = f_alloc_FlagBitsEnumProp(nullptr, *S_节点UI数据::g_对称轴枚举项, u"渲染图层");
	m_输出图层.m_私有 = true;
	f_prop_UI32位域枚举(m_输出图层) = 1;

	m_渲染世界 = f_alloc_Object(&S_节点数据::g_渲染世界数据, u"初始渲染层");
	m_渲染世界.m_私有 = true;

	m_场景遮罩 = f_alloc_FlagBitsUI8Prop(nullptr, u"场景遮罩", 0x7f);
	m_场景遮罩.m_私有 = true;


	m_帧渲染参数.m_Frame = 0;
	m_帧渲染参数.m_ParallelLightNum = 0;
	m_帧渲染参数.m_SpotLightNum = 0;
	m_帧渲染参数.m_PointLightNum = 0;
	m_帧渲染参数.m_AreaLightNum = 0;
	m_帧渲染参数.m_BouncesNum = 8;
	m_帧渲染参数.m_SamplesNum = 64;
	m_帧渲染参数.m_world_ShaderID = -1;
	m_帧渲染参数.m_ViewOffset_X = 0;
	m_帧渲染参数.m_ViewOffset_Y = 0;
	m_帧渲染参数.m_MaxZ = 5000;
	m_帧渲染参数.m_OutLayer_PreviewMode = DEF_RF_PM_composite | 1;

}

C_渲染器配置节点::~C_渲染器配置节点() {
	f_prop_Release(m_分辨率);
	f_prop_Release(m_光反弹);
	f_prop_Release(m_采样);
	f_prop_Release(m_瓦片渲染);
	f_prop_Release(m_瓦片大小);
	f_prop_Release(m_开启运动模糊);
	f_prop_Release(m_运动模糊采样);
	f_prop_Release(m_运动模糊时间);

	f_prop_Release(m_输出图层);
	f_prop_Release(m_渲染世界);
	f_prop_Release(m_场景遮罩);
}

bool C_渲染器配置节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* 摄像机 = DEF_物体插座数据(socket1, 0);
	if (摄像机 && 摄像机->m_Type != E_物体类型::t_摄像机) {
		摄像机 = f_ob_以类型查找子物体(摄像机, E_物体类型::t_摄像机);
	}

	auto scene = f_NodeCtx_get默认场景();
	S_材质管线* 材质 = DEF_材质插座数据(f_get输入插座(2), 0);
	if (材质 && 材质->m_着色线管 && 材质->m_着色线管->m_Shader) {
		m_帧渲染参数.m_world_ShaderID = f_buf_Material_at(材质->m_材质属性, 0).m_shaderIndex;

		if(scene->m_天空) f_ob_set材质(scene->m_天空, 材质, 0);
	}
	else {
		m_帧渲染参数.m_world_ShaderID = -1;

		if (scene->m_天空) f_ob_set材质(scene->m_天空, 材质, 0);
	}



	auto& e = (*S_节点数据::g_纹理预览容器[DEF_纹理容器槽_渲染输出]);
	if (e.size() <= E_RenderLayerType::e_renderLayer_composite) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_最终合成, u"合成", u"" });
	}
	if (e.size() <= E_RenderLayerType::e_renderLayer_diffuse) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_漫反射, u"颜色", u"" });
	}
	if (e.size() <= E_RenderLayerType::e_renderLayer_depth) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_深度, u"深度", u"" });
	}
	if (e.size() <= E_RenderLayerType::e_renderLayer_normal) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_法线, u"法线", u"" });
	}
	if (e.size() <= E_RenderLayerType::e_renderLayer_illuminate) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_自发光, u"自发光", u"" });
	}
	if (e.size() <= E_RenderLayerType::e_renderLayer_shadow) {
		e.push_back({ scene->m_光追后端->m_渲染纹理_光照, u"阴影", u"" });
	}


	switch (S_光追后端::g_渲染状态) {
		case E_离线渲染状态::e_光追渲染_单帧:
		case E_离线渲染状态::e_光追渲染_序列:
			break;
		default: return false;
	}


	S_渲染世界* 世界 = f_更新世界(scene);
	//auto* 渲染世界对象 = f_prop_Object(m_渲染世界);
	//if (渲染世界对象) {
	//	世界 = (S_渲染世界*)渲染世界对象->m_UserData;
	//}
	//else {
	//	f_scene_构建光追加速结构(scene);
	//	世界 = scene->m_默认渲染世界;
	//}


	if (摄像机) {
		auto 采样 = f_prop_UI32(m_采样);
		

		S_RayRenderAttr Attr;
		Attr.光采样 =  f_prop_UI32(m_光采样);
		Attr.反弹次数 = f_prop_UI32(m_光反弹);
		Attr.采样次数 = f_prop_UI32(m_采样);

		
		
		f_scene_设置光追渲染采样(scene, Attr);
		uvec2 分辨率 = f_prop_uVec2(m_分辨率);



		S_TexArray* 输出纹理 = DEF_纹理插座_1D数据(f_get输出插座(1));

		uint32 图层数量 = 0;
		uint32 图层位域 = f_prop_UI32位域枚举(m_输出图层);

		for (uint32 i = 0; i < 32; ++i) {
			if (图层位域 & (1 << i)) {
				++图层数量;
			}
		}
		f_core_array_resize((S_Array*)输出纹理, 图层数量);


		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_composite)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_最终合成, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_composite] = scene->m_光追后端->m_渲染纹理_最终合成;
		}
		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_diffuse)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_漫反射, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_diffuse] = scene->m_光追后端->m_渲染纹理_漫反射;
		}
		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_depth)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_深度, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_depth] = scene->m_光追后端->m_渲染纹理_深度;
		}
		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_normal)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_法线, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_normal] = scene->m_光追后端->m_渲染纹理_法线;
		}
		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_illuminate)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_自发光, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_illuminate] = scene->m_光追后端->m_渲染纹理_自发光;
		}
		if (图层位域 & (1 << E_RenderLayerType::e_renderLayer_shadow)) {
			f_tex_修改大小(scene->m_光追后端->m_渲染纹理_光照, { 分辨率.x, 分辨率.y, 1 }, true);
			输出纹理->ptr_userData[E_RenderLayerType::e_renderLayer_shadow] = scene->m_光追后端->m_渲染纹理_光照;
		}
		f_scene_set渲染器渲染层(scene, 图层位域);
		
		
		
		f_tex_修改大小(m_渲染纹理, { 分辨率.x, 分辨率.y, 1 }, true);

		dynamic_cast<S_摄像机*>(摄像机)->m_分辨率 = { int32(分辨率.x), int32(分辨率.y) };
		m_渲染纹理->m_命令缓存 = scene->m_光追后端->m_渲染命令缓存;


		S_摄像机* camera = dynamic_cast<S_摄像机*>(摄像机);
		if (camera) {
			auto& 帧 = f_NodeCtx_get帧();
			f_NodeCtx_set场景当前时间(S_节点数据::g_渲染帧编号);


			camera->f_set宽高比({ float32(分辨率.x), float32(分辨率.y) });
			if (scene->mf_渲染前Update) {
				scene->mf_渲染前Update((S_结构指针)this);
			}


			scene->f_载入纹理();
			f_world_更新输出纹理(世界, 分辨率, 图层位域);


			m_帧渲染参数.m_ViewSize = 分辨率;
			m_帧渲染参数.m_BouncesNum = f_prop_UI32(m_光反弹);
			m_帧渲染参数.m_LigthSamples = f_prop_UI32(m_光采样);
			m_帧渲染参数.m_SamplesNum = f_prop_UI32(m_采样);
			m_帧渲染参数.m_OutLayer_PreviewMode = 图层位域;
			m_帧渲染参数.m_SceneMask_ObMask = f_prop_U8位域(m_场景遮罩);


			f_render_刷新渲染(scene);
			m_帧渲染参数.m_Frame = 0;


			float32 子时间步进 = 1;
			int32 模糊采样次数 = 1;
			if (f_prop_Bool(m_开启运动模糊)) {
				float32 运动模糊采样 = min(f_prop_UI32(m_运动模糊采样), Attr.采样次数);
				模糊采样次数 = max(Attr.采样次数 / 运动模糊采样, 1);

				//子时间步进 = 帧.帧率 / Attr.采样次数;
				子时间步进 = (f_prop_F32(m_运动模糊时间) * 帧.帧率) / Attr.采样次数;
			}
			else {
				模糊采样次数 = Attr.采样次数;
				子时间步进 = 0;
			}


			if (f_prop_Bool(m_瓦片渲染)) {
				uvec2 瓦片大小 = f_prop_uVec2(m_瓦片大小);
				uvec2 瓦片数量 = 分辨率 / 瓦片大小;
				
				scene->m_光追后端->m_瓦片大小 = 瓦片大小;
				uvec2 多出分辨率 = 分辨率 - 瓦片数量 * 瓦片大小;

				if (分辨率.x > 瓦片大小.x * 瓦片数量.x) ++瓦片数量.x;
				if (分辨率.y > 瓦片大小.y * 瓦片数量.y) ++瓦片数量.y;


				for (uint32 i = 0; i < Attr.采样次数; ++i) {
					
					scene->m_光追后端->f_递增渲染帧记录();
					++m_帧渲染参数.m_Frame;

					int32 模糊采样编号 = i % 模糊采样次数;
					if (!模糊采样编号) {
						float32 帧步进 = (float32(i) * 子时间步进);
						float32 帧采样比 = 帧步进 - int32(帧步进);

						f_NodeCtx_set当前帧(S_节点数据::g_渲染帧编号 + 帧步进, 帧采样比);
						f_ob_set步进时间帧(帧.当前帧);

						scene->f_Update(camera);

						f_node_Step物体节点树();
						f_NodeCtx_执行模拟计算();
						f_OE_更新世界渲染空间物体();

						世界 = f_更新世界(scene);
						f_render_绑定参数(camera, m_帧渲染参数, *世界->m_渲染纹理_最终合成, 世界, scene->m_光追后端);
					}

					std::cout << "完成渲染采样:";

					for (uint32 y = 0; y < 瓦片数量.y; ++y) {
						for (uint32 x = 0; x < 瓦片数量.x; ++x) {
							if (S_光追后端::g_渲染状态 == E_离线渲染状态::e_光追渲染_关) goto To_结束渲染;

							scene->m_光追后端->m_渲染配置.m_瓦片ID = { x, y };


							m_帧渲染参数.m_ViewOffset_X = 瓦片大小.x * x;
							m_帧渲染参数.m_ViewOffset_Y = 瓦片大小.y * y;

							if (瓦片大小.x * x <= 分辨率.x) {
								scene->m_光追后端->m_渲染配置.m_瓦片分辨率.x = 瓦片大小.x;
							}
							else {
								scene->m_光追后端->m_渲染配置.m_瓦片分辨率.x = 分辨率.x - 瓦片大小.x * x;
							}

							if (瓦片大小.y * y <= 分辨率.y) {
								scene->m_光追后端->m_渲染配置.m_瓦片分辨率.y = 瓦片大小.y;
							}
							else {
								scene->m_光追后端->m_渲染配置.m_瓦片分辨率.y = 分辨率.y - 瓦片大小.y * y;
							}

							f_render_更新参数(m_帧渲染参数, 世界, scene->m_光追后端);
							std::cout << "瓦块X:" << x << " 瓦块Y:" << y << "\n";
							f_df_光追渲染(m_帧渲染参数, scene->m_光追后端);
							//scene->f_Ray准备渲染(camera, m_帧渲染参数, *世界->m_渲染纹理_最终合成, 世界, Attr.采样次数);
							if (!S_光追后端::g_渲染状态) break;
						}
					}
					std::cout << Attr.采样次数 << "/" << i << " ";
				}
			}
			else {
				m_帧渲染参数.m_ViewOffset_X = 0;
				m_帧渲染参数.m_ViewOffset_Y = 0;

				scene->m_光追后端->m_渲染配置.m_瓦片分辨率 = 分辨率;

				for (uint32 i = 0; i < Attr.采样次数; ++i) {
					scene->m_光追后端->f_递增渲染帧记录();
					++m_帧渲染参数.m_Frame;


					
					int32 模糊采样编号 = i % 模糊采样次数;
					
					if (!模糊采样编号) {
						float32 帧步进 = (float32(i) * 子时间步进);
						float32 帧采样比 = 帧步进 - int32(帧步进);

						f_NodeCtx_set当前帧(S_节点数据::g_渲染帧编号 + 帧步进, 帧采样比);
						f_ob_set步进时间帧(帧.当前帧);

						scene->f_Update(camera);

						f_node_Step物体节点树();
						f_NodeCtx_执行模拟计算();
						f_OE_更新世界渲染空间物体();

						世界 = f_更新世界(scene);
						f_render_绑定参数(camera, m_帧渲染参数, *世界->m_渲染纹理_最终合成, 世界, scene->m_光追后端);
					}

					f_df_光追渲染(m_帧渲染参数, scene->m_光追后端);

					std::cout << Attr.采样次数 << "/" << i << " ";
					if (!S_光追后端::g_渲染状态) break;
				}
				std::cout << "\n";
				//scene->f_Ray准备渲染(camera, m_帧渲染参数, *世界->m_渲染纹理_最终合成, 世界, Attr.采样次数);
			}

		}
	To_结束渲染:
		//输出纹理->ptr_userData[0] = scene->m_光追后端->m_渲染纹理_最终合成;
		输出纹理->ptr_userData[0] = 世界->m_渲染纹理_最终合成;
	}
	
	return false;
}

void C_渲染器配置节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_分辨率, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_光反弹, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_光采样, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_采样, 下一次读取数据指针);

		下一次读取数据指针 = f_prop_Load(m_瓦片渲染, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_瓦片大小, 下一次读取数据指针);

		下一次读取数据指针 = f_prop_Load(m_开启运动模糊, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_运动模糊采样, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_运动模糊时间, 下一次读取数据指针);

		下一次读取数据指针 = f_prop_Load(m_输出图层, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_渲染世界, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_场景遮罩, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_渲染器配置节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_分辨率, 块);
	f_prop_Save(m_光反弹, 块);
	f_prop_Save(m_光采样, 块);
	f_prop_Save(m_采样, 块);

	f_prop_Save(m_瓦片渲染, 块);
	f_prop_Save(m_瓦片大小, 块);

	f_prop_Save(m_开启运动模糊, 块);
	f_prop_Save(m_运动模糊采样, 块);
	f_prop_Save(m_运动模糊时间, 块);

	f_prop_Save(m_输出图层, 块);
	f_prop_Save(m_渲染世界, 块);
	f_prop_Save(m_场景遮罩, 块);

	f_file_保存文件块(f, 文件块, 块);
}

S_渲染世界* C_渲染器配置节点::f_更新世界(S_Scene* scene) {
	S_渲染世界* 世界;
	auto* 渲染世界对象 = f_prop_Object(m_渲染世界);
	if (渲染世界对象) {
		世界 = (S_渲染世界*)渲染世界对象->m_UserData;
	}
	else {
		f_scene_构建光追加速结构(scene);
		世界 = scene->m_默认渲染世界;
	}
	return 世界;
}

C_节点基类* f_node_创建渲染器配置节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染器配置节点(ctx);
}

C_节点基类* f_node_加载渲染器配置节点(S_设备环境& ctx, FILE* f) {
	C_渲染器配置节点* node = new C_渲染器配置节点(ctx);
	return node;
}

void f_node_保存渲染器配置节点(C_节点基类* n, FILE* f) {
	C_渲染器配置节点* node = dynamic_cast<C_渲染器配置节点*>(n);
}






static OIDNDevice gDevice = 0;

C_图像降噪节点::C_图像降噪节点(S_设备环境& ctx) : C_节点基类(DEF_图像降噪节点, E_节点类型::e_节点Type_渲染) {
	f_setWName(u"降噪");
	m_Ctx = ctx;
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	
	DEF_创建纹理_1D插座_I(u"图层", ctx);
	DEF_创建纹理插座_O(u"图像", ctx);


	m_加速计算方式 = f_alloc_EnumProp(nullptr, {
		{u"自动选择"},
		{u"CPU"},
		{u"SYCL"},
		{u"CUDA"},
		{u"HIP"},
	}, u"加速计算");
	m_加速计算方式.m_私有 = true;

	gDevice = oidnNewDevice(OIDNDeviceType(f_prop_enum(m_加速计算方式))); // CPU or GPU if available
	oidnCommitDevice(gDevice);

	m_输出纹理 = f_tex_创建图像(m_Ctx, {8,8,1}, E_纹理格式::e_tf_RGB32, E_纹理维度类型::e_2D);
	m_输出纹理->m_像素 = calloc(8*8*4, 4);

	m_临时缓存 = f_buf_create板载缓存(m_Ctx, E_板载缓存类型::e_SSBO, E_板载缓存类型::e_SSBO | E_板载缓存类型::e_拷贝目标, 4 * 4, 64 * 64);
}

C_图像降噪节点::~C_图像降噪节点() {
	f_tex_销毁纹理(m_输出纹理);
	f_buf_release板载缓存(m_临时缓存);
}

bool C_图像降噪节点::f_update() {
	switch (S_光追后端::g_渲染状态) {
		case E_离线渲染状态::e_光追渲染_单帧:
		case E_离线渲染状态::e_光追渲染_序列:
			break;
		default: return false;
	}

	S_TexArray* 输出纹理 = DEF_纹理插座_1D数据(f_get输入插座(1));

	uint32 width = 100;
	uint32 height = 100;

	OIDNBuffer colorBuf = nullptr;
	OIDNBuffer albedoBuf = nullptr;
	OIDNBuffer normalBuf = nullptr;
	OIDNBuffer outBuf = nullptr;
	OIDNFilter filter = oidnNewFilter(gDevice, "RT");

	
	

	if (输出纹理->count > DEF_renderLayer_albedo) {
		auto& t = 输出纹理->ptr_userData[DEF_renderLayer_albedo];
		albedoBuf = oidnNewBuffer(gDevice, t->m_Size.x * t->m_Size.y * sizeof(vec3));

		width = t->m_Size.x;
		height = t->m_Size.y;
		f_buf_resize(m_临时缓存, width * height);
		f_tex_读取纹理数据(t, m_临时缓存);

		//oidnSetFilterImage(filter, "albedo", albedoBuf, OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0);
		vec3* albedoPtr = (vec3*)oidnGetBufferData(albedoBuf);
		f_tex_转换格式读取纹理数据(m_临时缓存, albedoPtr, t->m_格式, E_纹理格式::e_tf_RGB32, width * height);
	}
	if (输出纹理->count > DEF_renderLayer_normal) {
		auto& t = 输出纹理->ptr_userData[DEF_renderLayer_normal];
		normalBuf = oidnNewBuffer(gDevice, t->m_Size.x * t->m_Size.y * sizeof(vec4));

		width = t->m_Size.x;
		height = t->m_Size.y;
		f_buf_resize(m_临时缓存, width * height);
		f_tex_读取纹理数据(t, m_临时缓存);

		//oidnSetFilterImage(filter, "normal", normalBuf, OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0);
		vec4* normalPtr = (vec4*)oidnGetBufferData(normalBuf);
		f_tex_转换格式读取纹理数据(m_临时缓存, normalPtr, t->m_格式, E_纹理格式::e_tf_RGB32, width * height);
	}
	if (输出纹理->count > DEF_renderLayer_composite) {
		auto& t = 输出纹理->ptr_userData[DEF_renderLayer_composite];
		colorBuf = oidnNewBuffer(gDevice, t->m_Size.x * t->m_Size.y * sizeof(vec3));
		outBuf = oidnNewBuffer(gDevice, t->m_Size.x * t->m_Size.y * sizeof(vec3));

		width = t->m_Size.x;
		height = t->m_Size.y;
		f_buf_resize(m_临时缓存, width * height);
		f_tex_读取纹理数据(t, m_临时缓存);

		oidnSetFilterImage(filter, "color", colorBuf, OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0);
		oidnSetFilterImage(filter, "output", outBuf, OIDN_FORMAT_FLOAT3, width, height, 0, 0, 0);


		vec3* colorPtr = (vec3*)oidnGetBufferData(colorBuf);
		f_tex_转换格式读取纹理数据(m_临时缓存, colorPtr, t->m_格式, E_纹理格式::e_tf_RGB32, width * height);
	}
	oidnSetFilterBool(filter, "hdr", false);
	oidnCommitFilter(filter);

	//oidnSetFilter1i(filter, "denoiseHDR", 1);
	//oidnSetFilter1f(filter, "hdrSharpness", 10.1);
	//oidnSetFilter1f(filter, "alpha", 1.0);
	//oidnSetFilter1i(filter, "spp", 16);
	//oidnSetFilter1f(filter, "pixelSpread", 0.5);

	//if (输出纹理->count > DEF_RF_RL_composite) {
	//	auto& t = 输出纹理->ptr_userData[DEF_RF_RL_composite];
	//	colorBuf = oidnNewBuffer(gDevice, t->m_Size.x * t->m_Size.y * sizeof(vec4));
	//}

	if (outBuf) {
		oidnExecuteFilter(filter);

		const char* errorMessage;
		if (oidnGetDeviceError(gDevice, &errorMessage) != OIDN_ERROR_NONE) {
			printf("Error: %s\n", errorMessage);
		}
		else {
			f_tex_修改大小(m_输出纹理, { width, height, 1 }, true);
			vec3* outPtr = (vec3*)oidnGetBufferData(outBuf);
			memcpy(m_输出纹理->m_像素, outPtr, width * height * sizeof(vec3));

		}
		oidnReleaseBuffer(colorBuf);
		oidnReleaseBuffer(albedoBuf);
		oidnReleaseBuffer(normalBuf);
	}
	
	oidnReleaseFilter(filter);

	f_get输出插座(1)->f_setData(m_输出纹理);
	return false;
}

void C_图像降噪节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_加速计算方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_图像降噪节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_加速计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建图像降噪节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_图像降噪节点(ctx);
}

C_节点基类* f_node_加载图像降噪节点(S_设备环境& ctx, FILE* f) {
	C_图像降噪节点* node = new C_图像降噪节点(ctx);
	return node;
}

void f_node_保存图像降噪节点(C_节点基类* n, FILE* f) {
	C_图像降噪节点* node = dynamic_cast<C_图像降噪节点*>(n);
}





C_渲染图层节点::C_渲染图层节点(S_设备环境& ctx) : C_节点基类(DEF_渲染输出节点, E_节点类型::e_节点Type_渲染) {
	
}

C_渲染图层节点::~C_渲染图层节点() {

}

bool C_渲染图层节点::f_update() {

	return false;
}

void C_渲染图层节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_图层类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_渲染图层节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_图层类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建渲染图层节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染图层节点(ctx);
}

C_节点基类* f_node_加载渲染图层节点(S_设备环境& ctx, FILE* f) {
	C_渲染图层节点* node = new C_渲染图层节点(ctx);
	return node;
}

void f_node_保存渲染图层节点(C_节点基类* n, FILE* f) {
	C_渲染图层节点* node = dynamic_cast<C_渲染图层节点*>(n);
}





C_渲染输出节点::C_渲染输出节点(S_设备环境& ctx) : C_节点基类(DEF_渲染输出节点, E_节点类型::e_节点Type_渲染) {
	f_setWName(u"渲染输出");
	m_Ctx = ctx;
	

	C_插座基类* socket;
	DEF_创建路径插座_I(u"路径");
	DEF_创建纹理插座_I(u"图像", ctx);

	m_相对路径 = f_alloc_BoolProp(nullptr, u"相对路径");
	m_相对路径.m_私有 = true;
	m_颜色通道 = f_alloc_EnumProp(nullptr, { {u"R", u""}, {u"RGB", u""}, {u"RGBA", u""} }, u"通道");
	m_颜色通道.m_私有 = true;

	m_写入方式 = f_prop_创建写入方式属性数据();
	m_写入方式.m_私有 = true;
	m_格式 = f_prop_创建图像格式类型属性数据();
	m_格式.m_私有 = true;
	m_位深 = f_prop_创建图像位宽类型属性数据();
	m_位深.m_私有 = true;
	

	DEF_路径插座(f_get输入插座(1))->m_Value.m_UI->m_Update = on_设置路径更新节点;

	auto& path = *DEF_路径插座数据(f_get输入插座(1), 0);
	path = std::filesystem::temp_directory_path().string();
	//path = f_String转码(std::filesystem::temp_directory_path().string(), "utf-8");
	
}

C_渲染输出节点::~C_渲染输出节点(){
	f_prop_Release(m_相对路径);
	f_prop_Release(m_颜色通道);
	f_prop_Release(m_写入方式);
	f_prop_Release(m_格式);
	f_prop_Release(m_位深);
}

bool C_渲染输出节点::f_update() {
	auto& path = *DEF_路径插座数据(f_get输入插座(1), 0);
	auto* 纹理 = DEF_纹理插座数据(f_get输入插座(2), 0);

	if (!纹理 || !(纹理->m_Size.x) || !(纹理->m_Size.y) || !(纹理->m_Size.z)) return false;

	auto 格式 = f_prop_enumName(m_格式);
	auto 位深 = (f_prop_enum(m_位深) + 1) * 4;


	auto 拼接路径 = f_nodeCtx_相对路径补全(path).u16string();
	
	
	f_file_创建目录(拼接路径);

	
	switch (S_光追后端::g_渲染状态) {
		case E_离线渲染状态::e_光追渲染_单帧:
			拼接路径 = f_file_补充文件路径后缀(拼接路径, 格式);
			//f_tex_保存到文件(纹理, path.string());
			f_tex_纹理写入到文件(纹理, f_str_u16_to_u8(拼接路径), 格式, 纹理->m_通道数量, 位深);
			std::cout << "保持图像:" << path << std::endl;
			break;

		case E_离线渲染状态::e_光追渲染_序列: {
			auto 文件路径 = f_file_get路径(拼接路径);
			auto 无后缀文件名 = f_file_get无后缀文件名(拼接路径);

			
			文件路径 += 无后缀文件名 + u"_" + f_str_string_to_u16(f_整数值转字符串(S_节点数据::g_渲染帧编号));
			文件路径 = f_file_补充文件路径后缀(文件路径, 格式);
			//f_tex_保存到文件(纹理, 文件路径);
			f_tex_纹理写入到文件(纹理, f_str_u16_to_u8(文件路径), 格式, 纹理->m_通道数量, 位深);
			//std::cout<<"保持图像:"<< 文件路径 << std::endl;
			break;
		}
	}
	
	return false;
}

void C_渲染输出节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_相对路径, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_颜色通道, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_位深, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_格式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_渲染输出节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_相对路径, 块);
	f_prop_Save(m_颜色通道, 块);
	f_prop_Save(m_位深, 块);
	f_prop_Save(m_格式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建渲染输出节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染输出节点(ctx);
}

C_节点基类* f_node_加载渲染输出节点(S_设备环境& ctx, FILE* f) {
	C_渲染输出节点* node = new C_渲染输出节点(ctx);

	return node;
}

void f_node_保存渲染输出节点(C_节点基类* n, FILE* f) {
	C_渲染输出节点* node = dynamic_cast<C_渲染输出节点*>(n);
}




C_渲染世界节点::C_渲染世界节点(S_设备环境& ctx) : C_节点基类(DEF_渲染世界节点, E_节点类型::e_节点Type_渲染) {
	
}

C_渲染世界节点::~C_渲染世界节点() {
	
}

bool C_渲染世界节点::f_update()
{
	return false;
}

void C_渲染世界节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_初始渲染层, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_渲染世界节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_初始渲染层, 块);

	f_file_保存文件块(f, 文件块, 块);
}


C_节点基类* f_node_创建渲染世界节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染世界节点(ctx);
}

C_节点基类* f_node_加载渲染世界节点(S_设备环境& ctx, FILE* f) {
	C_渲染世界节点* node = new C_渲染世界节点(ctx);

	return node;
}

void f_node_保存渲染世界节点(C_节点基类* n, FILE* f) {
	C_渲染世界节点* node = dynamic_cast<C_渲染世界节点*>(n);
}
